/**
 * Copyright (c) 2011 ~ 2013 Deepin, Inc.
 *               2011 ~ 2013 jouyouyun
 *
 * Author:      jouyouyun <jouyouwen717@gmail.com>
 * Maintainer:  jouyouyun <jouyouwen717@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 **/

package main

import (
        //libdbus "dbus/org/freedesktop/dbus"
        polkit1 "dbus/org/freedesktop/policykit1"
        "dlib/dbus"
        "os"
        "os/exec"
)

const (
        POLKIT_CHANGED_OWN_DATA = "org.freedesktop.accounts.change-own-user-data"
        POLKIT_MANAGER_USER     = "org.freedesktop.accounts.user-administration"
        POLKIT_SET_LOGIN_OPTION = "org.freedesktop.accounts.set-login-option"
)

type Manager struct{}

type polkitSubject struct {
        /*
         * The following kinds of subjects are known:
         * Unix Process: should be set to unix-process with keys
         *                  pid (of type uint32) and
         *                  start-time (of type uint64)
         * Unix Session: should be set to unix-session with the key
         *                  session-id (of type string)
         * System Bus Name: should be set to system-bus-name with the key
         *                  name (of type string)
         */
        SubjectKind    string
        SubjectDetails map[string]dbus.Variant
}

func (op *Manager) GetDBusInfo() dbus.DBusInfo {
        return dbus.DBusInfo{
                "com.deepin.example.TestPolikit",
                "/com/deepin/example/TestPolikit",
                "com.deepin.example.TestPolikit",
        }
}

func (op *Manager) AuthWithPolkit(id string, pid uint32) {
        authWithPolkit(id, pid)
        println("Authority: ", id)
}

func (op *Manager) Auth1(dbusMsg dbus.DMessage) {
        println("sender: ", dbusMsg.GetSender())
        println("Pid: ", dbusMsg.GetSenderPID())
        authWithPolkit(POLKIT_CHANGED_OWN_DATA, dbusMsg.GetSenderPID())
        println("Authority: ", POLKIT_CHANGED_OWN_DATA)
        args := []string{"/sbin/fdisk", "-l"}
        err := exec.Command("/usr/bin/sudo", args...).Run()
        if err != nil {
                println("Exec Failed: ", err.Error())
        }
}

func (op *Manager) Auth2(dbusMsg dbus.DMessage) {
        authWithPolkit(POLKIT_MANAGER_USER, dbusMsg.GetSenderPID())
        println("Authority: ", POLKIT_MANAGER_USER)
        args := []string{"/sbin/fdisk", "-l"}
        err := exec.Command("/usr/bin/sudo", args...).Run()
        if err != nil {
                println("Exec Failed: ", err.Error())
        }
}

func authWithPolkit(actionId string, pid uint32) {
        var (
                objPolkit *polkit1.Authority
                err       error
        )

        objPolkit, err = polkit1.NewAuthority("org.freedesktop.PolicyKit1",
                "/org/freedesktop/PolicyKit1/Authority")
        if err != nil {
                println("New Authority Failed:", err)
                panic(err)
        }

        subject := polkitSubject{}
        subject.SubjectKind = "unix-process"
        subject.SubjectDetails = make(map[string]dbus.Variant)
        subject.SubjectDetails["pid"] = dbus.MakeVariant(uint32(pid))
        subject.SubjectDetails["start-time"] = dbus.MakeVariant(uint64(0))
        details := make(map[string]string)
        details[""] = ""
        flags := uint32(1)
        cancelId := ""

        _, _err := objPolkit.CheckAuthorization(subject, actionId, details, flags, cancelId)
        if _err != nil {
                println("CheckAuthorization Failed:", _err)
                panic(_err)
        }
}

func main() {
        m := &Manager{}
        //err := dbus.InstallOnSession(m)
        err := dbus.InstallOnSystem(m)
        if err != nil {
                println("InstallOnSystem Error: ", err)
                panic(err)
        }
        dbus.DealWithUnhandledMessage()
        println("pid:", os.Getpid())

        if err = dbus.Wait(); err != nil {
                println("lost dbus session:", err)
                os.Exit(1)
        } else {
                os.Exit(0)
        }
}
